`timescale 1ns/1ns
`define k 256
`define m 16
`define p_256r1 256'hffffffff00000001000000000000000000000000ffffffffffffffffffffffff
`define n_256r1 256'hFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
`define p_sm2 256'hFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF
`define n_sm2 256'hFFFFFFFE_FFFFFFFF_FFFFFFFF_FFFFFFFF_7203DF6B_21C6052B_53BBF409_39D54123


module RS_A(input clk,
			input rst_n,
			input enable,
			input curve_sel,
			input mod,//0 mod p
					  //1 mod n
			//input [`k+`m+2:0] csa_out,
			input [`k+`m+1:0] csa_out,
			//input [`k:0] add_out,
			input [`k-1:0] add_out,
			input [`k+`m+2:0] c,
			//input [`k:0] u,
			input u,
			//input [`k:0] v,
			input [`k-1:0] v,
			//input [`k+`m+2:0] csa_in1,
			input csa_in1,
			//input [`k+`m+2:0] csa_in2,
			input [1:0] csa_in2,
			output [`k+`m+2:0] sc,
			output [`k:0] uv,
			output reg [3:0] csa_sel,
			output reg [3:0] csa_p_sel,
			output reg [3:0] add_sel,
			output reg [8:0] r_sel,
			output [`k-1:0] r,
			output end_flag,
			output reg busy
		   );
		   
//wire [`k-1:0] p;

reg [2:0] state,next_state;

//wire [`k+`m+2:0] sc1;
//wire [`k:0] uv1;

parameter IDLE = 3'b001,
		  READ = 3'b010,
		  LOOP = 3'b100;
		  
always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		state <= IDLE;
	end
	else
	begin
		state <= next_state;
	end
end

always @(*)
begin
	case(state)
	IDLE : if(enable)
			next_state = READ;
		   else
			next_state = IDLE;
	READ:	next_state = LOOP;
	LOOP : if(end_flag)
			next_state = IDLE;
		   else
			next_state = LOOP;
	default : next_state = IDLE;
	endcase
end

always @(*)
begin
	case(state)
	IDLE : r_sel = 9'b10_10_111_11;
	READ : r_sel = 9'b11_11_011_11;
	LOOP : if(uv[256])
			r_sel = 9'b00_01_000_10;
		   else
			r_sel = 9'b01_00_010_00;
	default : r_sel = 9'b0;
	endcase
end

always @(*)
begin
	case(state)
	/*IDLE : begin
			csa_sel = 4'b0;
			add_sel = 4'b0;
		   end
	READ : begin
			csa_sel = 4'b0;
			add_sel = 4'b0;
		   end
	*/
	LOOP : begin
			if((v[0] == 1'b1) & (u == 1'b1))
			begin
				csa_sel = 4'b1010;
				add_sel = 4'b1010;
			end
			else if((v[0] == 1'b1) & (u == 1'b0))
			begin
				csa_sel = 4'b0010;
				add_sel = 4'b0010;
			end
			else
			begin
				csa_sel = 4'b1000;
				add_sel = 4'b1000;
			end
			/*
			else if((v[0] == 1'b0) & (u == 1'b1))
			begin
				csa_sel = 4'b1000;
				add_sel = 4'b1000;
			end
			*/
			/*else if((v[0] == 1'b0) & (u == 1'b0))
			begin
				csa_sel = 4'b0000;
				add_sel = 4'b0000;
			end
			*/
			/*
			else
			begin
				csa_sel = 4'b0000;
				add_sel = 4'b0000;
			end
			*/
		   end
	default : begin
				csa_sel = 4'b0000;
				add_sel = 4'b0000;
			end
	endcase
end

always @(*)
begin
	case(state)
	IDLE : csa_p_sel = 4'b0000;
	READ : csa_p_sel = 4'b0000;
	LOOP :if(curve_sel == 1'b0)
			if((csa_in1 ^ csa_in2[0]) == 1'b0)
				csa_p_sel = 4'b0001;
			/*else if((csa_in2[1])&&(mod == 1'b0))
				csa_p_sel = 4'b0100;
			else if((csa_in2[1])&&(mod == 1'b1))
				csa_p_sel = 4'b0011;
			*/
			else if(csa_in2[1])
				if(mod == 1'b0)
					csa_p_sel = 4'b0100;
				else
					csa_p_sel = 4'b0011;
			else
				if(mod == 1'b0)
					csa_p_sel = 4'b0010;
				else
					csa_p_sel = 4'b1000;
		  else
			if((csa_in1 ^ csa_in2[0]) == 1'b0)
				csa_p_sel = 4'b0001;
			/*else if((csa_in2[1])&&(mod == 1'b0))
				csa_p_sel = 4'b1100;
			else if((csa_in2[1])&&(mod == 1'b1))
				csa_p_sel = 4'b0111;
			*/
			else if(csa_in2[1])
				if(mod == 1'b0)
					csa_p_sel = 4'b1100;
				else
					csa_p_sel = 4'b0111;
			else
				if(mod == 1'b0)
					csa_p_sel = 4'b1101;
				else
					csa_p_sel = 4'b1111;
	default : csa_p_sel = 4'b0000;
	endcase
end

//assign p = (curve_sel == 1'b0) ? ((mod == 1'b0) ? `p_256r1 : `n_256r1) : ((mod == 1'b0) ? `p_sm2 : `n_sm2);

//assign sc1 = csa_out >> 1'b1;
//assign sc = {csa_out[274],sc1[273:0]};
assign sc = {csa_out[273],csa_out};


//assign uv1 = add_out >> 1'b1;
//assign uv = {add_out[256],uv1[255:0]};
assign uv = {add_out[255],add_out};

//assign r = (c[`k+`m+2]==1) ? c + p : ((c > {19'b0,p}) ? c - p : c);

assign r = (curve_sel == 1'b0) ? ((mod == 1'b0) ? ((c[`k+`m+2]==1) ? c + `p_256r1 : ((c > {19'b0,`p_256r1}) ? c - `p_256r1 : c)) : ((c[`k+`m+2]==1) ? c + `n_256r1 : ((c > {19'b0,`n_256r1}) ? c - `n_256r1 : c))) : ((mod == 1'b0) ? ((c[`k+`m+2]==1) ? c + `p_sm2 : ((c > {19'b0,`p_sm2}) ? c - `p_sm2 : c)) : ((c[`k+`m+2]==1) ? c + `n_sm2 : ((c > {19'b0,`n_sm2}) ? c - `n_sm2 : c)));

assign end_flag = ((state == LOOP)&(v == 1)) ? 1'b1 : 1'b0;

always @(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		busy <= 1'b0;
	end
	else if(enable)
	begin
		busy <= 1'b1;
	end
	else if((state == LOOP) & (next_state == IDLE))
	begin
		busy <= 1'b0;
	end
end

endmodule